package com.supermap.wzhy.module.fr.service;

import com.supermap.wzhy.data.ConfigHelper;
import com.supermap.wzhy.data.OpStatus;
import com.supermap.wzhy.entity.TMicroIdenmeta;
import com.supermap.wzhy.entity.TMicroTablemeta;
import com.supermap.wzhy.entity.TUsertask;
import com.supermap.wzhy.module.data.dao.MicroIdenmetaDao;
import com.supermap.wzhy.module.data.dao.MicroTablemetaDao;
import com.supermap.wzhy.module.fr.dao.FrDao;
import com.supermap.wzhy.module.fr.dao.WjgDao;
import com.supermap.wzhy.module.user.dao.UserTaskDao;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 导出文件柜数据服务类
 * Created by W.Qiong on 16-12-26.
 */
@Service
public class FrWjgService {
    private final  static String BASE_TABLE ="YZYM_E_BASEINFO";
    private  final  static String UNIQ_FIELD ="ETPSID" ; //唯一标识字段
    //子报表
    private final  static String[] SUB_TABLES =new String[]{"YZYM_E_BASEINFO","YZYM_E_LEREP","YZYM_E_FINANCE","YZYM_E_INV"
                                                ,"","","YZYM_E_ALT","YZYM_E_CANCEL"};
    //子报表节点
    private final  static String[] SUB_TABLES_NODES =new String[]{"RECORD","LEREP","INFOFINANCE","INVESTORLIST-INVESTORDOCUMENT"
            ,"CHILDENTLIST-CHILDENT","PARENTENTDOCUMENT","INFOALTS-INFOALT","INFOCANCLE"};



    @Autowired
    FrDao frDao ;
    @Autowired
    MicroTablemetaDao microTablemetaDao ;
    @Autowired
    MicroIdenmetaDao microIdenmetaDao ;
    @Autowired
    UserTaskDao userTaskDao ;
    @Autowired
    WjgDao wjgDao;

    @Autowired
    TableTempService tableTempService;


    /**
     * 得到基本信息表名
     * @return 表名集合
     */
    public List getAllTable(){
        String sql = "select table_name from t_micro_tablemeta where miccatalog = 'FR_JBXX'";
        List<String> list = microTablemetaDao.query(sql);
        return  list;
    }

    /**
     * 得到基本信息表名 2.0
     * @return 表名集合
     */
    public List getGSTable(){
        String sql = "select mitmid,name from t_micro_tablemeta where miccatalog = 'FR_JBXX'";
        List<String> list = microTablemetaDao.query(sql);
        return  list;
    }


    /**
     * 得到基本信息表指标 2.0
     * @return 指标集合
     */
    public List getGSIden(String mitmid){
        String table_sql = "select iden_code,iden_name from t_micro_idenmeta where mitmid = ?";
        List<String> list = new ArrayList<>();
        if (mitmid == null || mitmid == "")
            list = microTablemetaDao.query(table_sql,"1");
        else
            list = microTablemetaDao.query(table_sql,mitmid);
        return  list;
    }


    /**
     * 得到所有年报表名
     * @return 表名集合
     */
    public List getNBTable(){
        String sql = "select table_name from t_micro_tablemeta where miccatalog = 'FR_NBXX'";
        List<String> list = microTablemetaDao.query(sql);
        return  list;
    }


    public List getNBYear(){
        String sql = "select ancheyear from YZYM_AN_BASEINFO group by ancheyear";
       return getResultList(sql);
    }


    public List getResultList(String sql){
        return frDao.query(sql);
    }

    /**
     * 检查是否有文件柜导出任务
     * @return
     */
    private  boolean checkWjgTaskRun(){
        return  userTaskDao.findRunningTask("wjg").size()>0; //后面再讲wjg写成常量

    } ;

    /**
     * 获取正在运行的文件柜导出任务
     * @return
     */
    public   List<TUsertask>  getRunWjgTask(){
        return  userTaskDao.findRunningTask("wjg"); //后面再讲wjg写成常量

    } ;




    /**
     * 启动导出文件柜线程
     * @param request
     * @param startTime
     * @param endTime
     * @return
     */
    public OpStatus  startRunnable(HttpServletRequest request ,Date startTime,Date endTime,int maxSize){
        try {

            FrWjgExpRunnable  frwjg = new FrWjgExpRunnable() ;

            if(frwjg.checkIsRun()){
                System.out.println("有导出任务正在执行，请稍后再尝试！");
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }else {

            }
            //程序没有在执行 库中有执行任务 ，删除
            if(checkWjgTaskRun()&&!frwjg.checkIsRun()){
                List<TUsertask> tUsertaskList  = userTaskDao.findRunningTask("wjg") ;
                userTaskDao.delete(tUsertaskList);
            }

            if(checkWjgTaskRun()){
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }

            frwjg.setDao(frDao,microTablemetaDao,microIdenmetaDao,userTaskDao,wjgDao);
            frwjg.setTime(startTime,endTime);
            frwjg.setMaxSize(maxSize);
            frwjg.setUserName(request);
            frwjg.run();
            System.out.println("任务导出已完成！");
            return  new OpStatus(true,"已添加任务，请耐心等待！",null) ;
        }   catch ( Exception e){
            e.printStackTrace();
        }
        return  new OpStatus(false,"创建文件柜导出任务失败！内部错误 e1-w-01，请联系技术人员",null) ;
    }



    /**
     * 启动年报导出文件柜线程
     * @param request
     * @param startTime
     * @param endTime
     * @return
     */
    public OpStatus  startNbRunnable(HttpServletRequest request ,Date startTime,Date endTime,int maxSize,String year){
        try {

            //FrNbExpRunnable2 frnb = new FrNbExpRunnable2();

            GSYearReportService yearReportService = new GSYearReportService();


            if(yearReportService.checkIsRun()){
                System.out.println("有导出任务正在执行，请稍后再尝试！");
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }else {

            }
            //程序没有在执行 库中有执行任务 ，删除
            if(checkWjgTaskRun()&&!yearReportService.checkIsRun()){
                List<TUsertask> tUsertaskList  = userTaskDao.findRunningTask("nb") ;
                userTaskDao.delete(tUsertaskList);
            }

            if(checkWjgTaskRun()){
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }

            yearReportService.setDao(frDao,microTablemetaDao,microIdenmetaDao,userTaskDao,wjgDao,tableTempService);
            yearReportService.setTime(startTime,endTime);
            yearReportService.setMaxSize(maxSize);
            yearReportService.setUserName(request);
            yearReportService.setYear(year);
            yearReportService.run();

            System.out.println("年报任务导出已完成！");
            return  new OpStatus(true,"已添加任务，请耐心等待！",null) ;
        }   catch ( Exception e){
            e.printStackTrace();
        }
        return  new OpStatus(false,"创建年报文件柜导出任务失败！内部错误 e1-n-02，请联系技术人员",null) ;
    }



    /**
     * 启动年报违法失信和经营异常导出文件柜线程
     * @param request
     * @param startTime
     * @param endTime
     * @return
     */
    public OpStatus startWFSXRunnable(HttpServletRequest request ,Date startTime,Date endTime,int maxSize){
        try {

            FrWFSXExpRunnable wfsx = new FrWFSXExpRunnable();
            FrJYYCExpRunnable jyyc = new FrJYYCExpRunnable();

            if(wfsx.checkIsRun()){
                System.out.println("有导出任务正在执行，请稍后再尝试！");
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }else {

            }
            //程序没有在执行 库中有执行任务 ，删除
            if(checkWjgTaskRun()&&!wfsx.checkIsRun()){
                List<TUsertask> tUsertaskList  = userTaskDao.findRunningTask("nb") ;
                userTaskDao.delete(tUsertaskList);
            }

            if(checkWjgTaskRun()){
                return  new OpStatus(false,"操作失败！有导出任务正在执行，请稍后再尝试！",null) ;
            }

            wfsx.setDao(frDao,microTablemetaDao,microIdenmetaDao,userTaskDao,wjgDao);
            wfsx.setTime(startTime,endTime);
            wfsx.setMaxSize(maxSize);
            wfsx.setUserName(request);
            wfsx.run();
            System.out.println("违法失信任务导出已完成！");

            jyyc.setDao(frDao,microTablemetaDao,microIdenmetaDao,userTaskDao,wjgDao);
            jyyc.setTime(startTime,endTime);
            jyyc.setMaxSize(maxSize);
            jyyc.setUserName(request);
            jyyc.run();
            System.out.println("经营异常任务导出已完成！");

            return  new OpStatus(true,"已添加任务，请耐心等待！",null) ;
        }   catch ( Exception e){
            e.printStackTrace();
        }
        return  new OpStatus(false,"创建违法失信或经营异常导出任务失败！内部错误 e1-n-03，请联系技术人员",null) ;
    }


    public OpStatus stopWjgTask(){
        OpStatus op = new OpStatus(true,"清空任务已成功!",null);
        String sql = "delete from t_usertask where task_type = 'wjg'";
        int i = userTaskDao.executeBySql(sql);
        System.out.println(i);
        if(i != 0){
            op.setStatus(true);
        }else{
            op.setStatus(false);
        }
        return op;
    }


    public OpStatus stopNbTask(){
        OpStatus op = new OpStatus(true,"清空年报任务已成功!",null);
        String sql = "delete from t_usertask where task_type = 'nb'";
        int i = userTaskDao.executeBySql(sql);
        System.out.println(i);
        if(i != 0){
            op.setStatus(true);
        }else{
            op.setStatus(false);
        }
        return op;
    }



    public String getCounts(String task_type){

        String sql = "select * from t_usertask where finished = '0' and task_type = '"+task_type+"'";

        List list = userTaskDao.query(sql);

        Object [] obj = list.toArray();

        String count = "";
        String completed = "";

        if(list.size() > 0){
            Object [] s = (Object [])obj[0];
            if(s != null){
                count = s[6].toString(); //导出总数
                completed = s[7].toString(); //当前导出数
            }
        }

        return completed+"/"+count;
    }

    /**
     * 生成文件柜数据入口
     * @param request
     * @param startTime
     * @param endTime
     */
    public OpStatus  start(HttpServletRequest request ,Date startTime,Date endTime){
        if(checkWjgTaskRun()){
            return  new OpStatus(false,"有导出任务正在执行，请稍后执行！",null) ;
        }
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String sql ="select * from "+BASE_TABLE;
        Object[] params = new Object[2];
        String startTimeStr = "";
        String endTimeStr ="";
        int i =0 ;
        if(startTime==null){
            startTimeStr = "2000-1-1 00:00:00";
        }
        if(endTime==null){
            endTimeStr = formatter.format(new Date());
        }
        params[0] = startTimeStr ;
        params[1] = endTimeStr ;
        sql =" from "+BASE_TABLE+" where  S_EXT_TIMESTAMP>= to_date(?,'yyyy-mm-dd hh24:mi:ss') and S_EXT_TIMESTAMP < to_date(?,'yyyy-mm-dd hh24:mi:ss') ";
       //找到单位记录总数
        Integer count = frDao.getIntegerUniq("select count(*) "+ sql,params) ;
       //计算总xml个数
        int perSize = 20000 ; //每次取出两万条
        int num = count/perSize+(count%perSize==0?0:1);
        Map<String ,List<TMicroIdenmeta>> idenMap = new HashMap<>() ;//指标元数据
        //读取全部报表元数据 第一个为基本信息表
        for(String t:SUB_TABLES){
            List<TMicroTablemeta>  tablemetaList  = microTablemetaDao.findByTableName(t);
            if(tablemetaList.size() ==0){
                continue;
            }
            TMicroTablemeta tablemeta  = tablemetaList.get(0) ;
            idenMap.put(t,microIdenmetaDao.findByWJGIden(tablemeta.getMitmid())) ;
        }
        //添加任务
        TUsertask usertask = addTask(count,"wjg");
        //取一定数目数据
        for(i =1 ; i< num+1 ;i++ ){
             int start = (i-1)*perSize ;
             int end = i*perSize ;
            List<Object[]> dataM = frDao.queryByPage("select  ETPSID ID,"+getQueryFields(idenMap.get(BASE_TABLE))+
                    sql,start,end,params) ;
//            Document document = DocumentHelper.createDocument();
            Element data = DocumentHelper.createElement("Data");
            boolean  needExp = false ;
            //逐条遍历数据
            for(int d= 0; d<dataM.size() ;d++){
                Element record = createRecord(d,dataM.get(d),idenMap.get(BASE_TABLE));
                String id =  dataM.get(d)[0].toString() ;//单位唯一标识
                //遍历报表取出子节点数据
                Object[] params1 =new Object[3] ;
                params1[0] = params[0] ;
                params1[1] =params[1] ;
                params1[2] = id ;
                needExp = true ;
                for(int j=1 ; j< SUB_TABLES.length;j++){
                    List<Object[]> dataList = frDao.query("select  " + getQueryFields(idenMap.get(SUB_TABLES[j])) +
                            sql+" and ETPSID=?", params1) ;
                    Element subTNode = createSubNode(SUB_TABLES_NODES[j],dataList,idenMap.get(SUB_TABLES[j])) ;
                    record.add(subTNode);
                }
                data.add(record);
                //每100条输出文件
                if((d+1)%100 == 0){
                    expOneXmlFile(data);
                    needExp =false ;
                    data = null ;
                    data = DocumentHelper.createElement("Data");
                    //更新进度
                    updateTask((i-1)*perSize+d,usertask) ;
                }
            }
            //剩余部分再导出
            if(needExp){
                expOneXmlFile(data);
                needExp =false ;
                //更新进度
                updateTask(i*perSize,usertask) ;
            }
        }
        //更新进度
        usertask.setFinished(1);
        updateTask(count,usertask) ;


        return  new OpStatus(true,"已添加任务，请耐心等待！",null) ;
    }

    /**
     * 添加文件柜导出任务
     * @param count
     * @param type
     * @return
     */
    private TUsertask  addTask(int count,String type){
        TUsertask t = new TUsertask() ;
        t.setTaskType(type);
        t.setStarttime(new Date());
        t.setCount(count + "");
        t.setFinished(0); //未完成标识
        return  userTaskDao.save(t) ;
    };


    private TUsertask  updateTask(int completed,TUsertask task){
        task.setCompleted(completed+"");
        return  userTaskDao.save(task) ;
    };

    /**
     * 导出xml文件
     * @param data
     * @return
     */
    private boolean expOneXmlFile(Element data){
        //根节点
        Element root = DocumentHelper.createElement("Package");
        Element head = createHead() ;//数据头部描述信息
        root.add(head);
        root.add(data);
        //输出文件
        createXmlFile(root);
        return true ;
    }

    /**
     * 创建单位数据基本信息节点
     * @param index
     * @param data
     * @param idenmetas
     * @return
     */
    private  Element createRecord(int index ,Object[] data,List<TMicroIdenmeta> idenmetas){

        Element record = DocumentHelper.createElement("Record") ;
        record.addAttribute("index",index+"") ;
        int len = idenmetas.size();
        for(int i =0 ; i< len ;i++){
            int type = idenmetas.get(i).getIdenType() ;
            String value = "";
            //格式化日期类型
            if(type == 3){
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                value = formatter.format(data[i]) ;
            }else{
                value = data[i]!=null?data[i].toString():"" ;
            }
            record.addElement(idenmetas.get(i).getIdenCode().toUpperCase(),value) ;
        }
        return  record ;
    }

    /**
     * 获取子报表的节点
     * @param nodeName
     * @param dataList
     * @param idenmetas
     * @return
     */
    private  Element createSubNode(String nodeName ,List<Object[]>dataList,List<TMicroIdenmeta> idenmetas){
        String[] nodes = nodeName.split("-") ;//多个则要考虑多个子节点
        Element rootNode = DocumentHelper.createElement(nodes[0]) ;
        int len = idenmetas.size();
        if(nodes.length>1){}
        for(Object[] data:dataList){
            Element subNode = nodes.length>1?DocumentHelper.createElement(nodes[1]):null ;
            for(int i =0 ; i< len ;i++){
                int type = idenmetas.get(i).getIdenType() ;
                int dsize = dataList.size() ;
                String value = "";
                //格式化日期类型
                if(type == 3){
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    value = formatter.format(data[i]) ;
                }else{
                    value = data[i]!=null?data[i].toString():"" ;
                }
                if(subNode == null){
                    rootNode.addElement(idenmetas.get(i).getIdenCode().toUpperCase(),value) ;
                }
                else{
                    subNode.addElement(idenmetas.get(i).getIdenCode().toUpperCase(),value) ;
                }
            }
            if(subNode != null){
                rootNode.add(subNode) ;
            }
        }
        return  rootNode ;
    }

    /**
     * 输出xml文件到指定目录
     * @param root
     * @return
     */
    private  boolean createXmlFile(Element root){
        //设置文件编码
        OutputFormat xmlFormat = new OutputFormat();
        xmlFormat.setEncoding("GB2312");
        // 设置换行
        xmlFormat.setNewlines(true);
        // 生成缩进
        xmlFormat.setIndent(true);
        // 使用4个空格进行缩进, 可以兼容文本编辑器
        xmlFormat.setIndent("    ");
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String fileName = formatter.format(new Date())+UUID.randomUUID()+".xml";
        String path = ConfigHelper.get("wjgpath")+"/"+fileName ;
        File f = new File(ConfigHelper.get("wjgpath")) ;
        if(!f.exists()){ f.mkdirs() ;}
        try {
            Document document = DocumentHelper.createDocument();
            document.add(root);
            //创建写文件方法
            XMLWriter xmlWriter = new XMLWriter(new FileWriter(path),xmlFormat);
            //写入文件
            xmlWriter.write(document);
            //关闭
            xmlWriter.close();
            return  true ;
        }   catch (Exception e){
            e.printStackTrace();
        }
        return  false ;

    }

    /**
     * 构造表头
     * @return
     */
    private Element createHead(){

        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddhhmmss");
        Element root = DocumentHelper.createElement("PackageHead") ;
        root.addEntity("SJBBH","");   // 数据包编号
        root.addEntity("SJBLX","") ;  //数据包类型
        root.addEntity("DWDM","") ;    //单位代码
        root.addEntity("DWMC","") ;    //单位名称
        root.addEntity("JLS","") ;     //记录数
        root.addEntity("INFODATE",formatter.format(new Date())) ;  //数据包生成时间，格式为yyyyMMddhhmmss
        return  root ;
    }

    /**
     * 获取查询指标字符串
     * @param idenmetas
     * @return
     */
    private String  getQueryFields(List<TMicroIdenmeta> idenmetas){
        StringBuilder b = new StringBuilder() ;
        int index =0 ;
        int size = idenmetas.size() ;
        for(TMicroIdenmeta i:idenmetas){
            b.append(i.getIdenCode().toUpperCase());
            if(index <size-1){
                b.append(",");
            }
            index++ ;
        }
        return b.toString() ;
    }
}
